using System.Collections.Generic;
using Lichtspiel.Display;
using Lichtspiel.ECSystem.Behaviors;
using Lichtspiel.Math;

namespace Lichtspiel.ECSystem
{
    public class Entity : Node<Entity>
    {
        private static int instances = 0;
        private readonly List<Behavior> behaviors = new List<Behavior>();

        private readonly List<Component> components = new List<Component>();
        private readonly string id;
        private readonly int instanceNumber = 0;
        private RenderComponent renderComponent;


        private float rotation = 0;

        public string ID {
            get { return id; } // todo id in node verschieben
        }

        public Vector2 Position { get; set; }

        public AnchorLocation Anchor { get; set; }

        public Vector2 Scale { get; set; }

        public Color Color { get; set; }

        /// <summary>
        /// Gets and Sets the Alpha value of the Color
        /// [0..1]
        /// </summary>
        public float Alpha {
            get { return Color.A; }

            set { Color = new Color(this.Color, value); }
        }

        /// <summary>
        /// Gets or sets the rotation angle in degrees.
        /// Positive angles indicate rotation in the Counter-Clockwise direction.
        /// </summary>
        public float Rotation {
            get { return rotation; }
            set { rotation = value % 360; }
        }

        public Entity(string id)
            : this(id, Vector2.Zero) {
            
        }

        public Entity(string id, Vector2 position) 
            : this(position) {
            this.id = id;
        }

        public Entity()
            : this(Vector2.Zero) {}

        public Entity(Vector2 position) {
            instanceNumber = instances;
            instances++;

            id = "Unknown" + GetType().Name + instanceNumber;

            Position = position;
            Scale = new Vector2(1, 1);
            this.Color = Color.White;
            Rotation = 0;

            Anchor = AnchorLocation.TopLeft;
        }

        public override void Render() {
            if (renderComponent != null) {
                renderComponent.Render();
            }

            // render children
            GLHelper.Translate(Position.X, Position.Y);
            GLHelper.Rotate(Rotation);
            GLHelper.Scale(Scale.X, Scale.Y);
            base.Render();
            GLHelper.Scale(1/Scale.X, 1/Scale.Y);
            GLHelper.Rotate(-Rotation);
            GLHelper.Translate(-Position.X, -Position.Y);
        }

        public override void Update(GameTime time) {
            for (int i = components.Count - 1; i >= 0; i--) {
                components[i].Update(time);
            }

            for (int i = behaviors.Count - 1; i >= 0; i--) {
                behaviors[i].Update(time);
            }

            base.Update(time);
        }

        public void AddComponent(Component component) {
            components.Add(component);
            component.Owner = this;

            var rc = component as RenderComponent;
            if (rc != null) {
                renderComponent = rc;
            }

            component.Initialize();
        }

        public T GetComponent<T>() where T : Component {
            if (renderComponent != null && renderComponent.GetType().IsSubclassOf(typeof (T))) {
                return renderComponent as T;
            }

            foreach (Component c in components) {
                if (c.GetType() == typeof (T)) {
                    return c as T;
                }
            }

            return null;
        }
//
//        public Component GetComponent(string id) {
//            if (renderComponent != null && renderComponent.ID == id) {
//                return renderComponent;
//            }
//
//            foreach (Component c in components) {
//                if (c.ID == id) {
//                    return c;
//                }
//            }
//
//            return null;
//        }

        public void Move(Vector2 offset) {
            Position += offset;
        }

        public void Rotate(float offset) {
            Rotation += offset;
        }

        public void AdjustScale(Vector2 factor) {
            Scale *= factor;
        }

        public void RunBehavior(Behavior behavior) {
            behaviors.Add(behavior);
            behavior.Initialize(this, null);
        }

        public void StopAllBehaviors() {
            foreach (Behavior b in behaviors) {
                b.Stop();
            }

            behaviors.Clear();
        }

        internal void BehaviorFinished(Behavior behavior) {
            StopBehavior(behavior);
        }

        public void StopBehavior(Behavior behavior) {
            behavior.Stop();
            behaviors.Remove(behavior);
        }
    }
}